/*/////////////////////////////////////////////////////////////////////////////////
/// An
///    ___   ____ ___ _____ ___  ____
///   / _ \ / ___|_ _|_   _/ _ \|  _ \
///  | | | | |  _ | |  | || | | | |_) |
///  | |_| | |_| || |  | || |_| |  _ <
///   \___/ \____|___| |_| \___/|_| \_\
///                              File
///
/// Copyright (c) 2008-2009 Ismail TARIM <ismail@royalspor.com> and the Ogitor Team
//
//This program is free software; you can redistribute it and/or modify it under
//the terms of the GNU Lesser General Public License as published by the Free Software
//Foundation; either version 2 of the License, or (at your option) any later
//version.
//
//This program is distributed in the hope that it will be useful, but WITHOUT
//ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
//FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public License along with
//this program; if not, write to the Free Software Foundation, Inc., 59 Temple
//Place - Suite 330, Boston, MA 02111-1307, USA, or go to
//http://www.gnu.org/copyleft/lesser.txt.
////////////////////////////////////////////////////////////////////////////////*/

#pragma once

// Includes
#include "ViewGrid.h"

namespace Ogitors
{

struct COMPOSITORPUSH
{
    Ogre::String name;
    bool         enabled;
};

class OgitorExport CViewportEditor: public CBaseEditor
{
    friend class CViewportEditorFactory;
public:
    static OgitorsPropertyDefMap propertyDefs;

    /// Returns the Factory associated with this object
	static CBaseEditorFactory *getFactory();
    /// Returns the Factory associated with this object can be overridden
	virtual CBaseEditorFactory *getFactoryDynamic();

    void          setIndex(const int& value, bool display);
    int           getIndex();
    void          setPlacement(const Ogre::Vector4& value, bool display);
    Ogre::Vector4 getPlacement();
    void          setOverlays(const bool& value, bool display);
    bool          getOverlays();
    void          setSkies(const bool& value, bool display);
    bool          getSkies();
    void          setShadows(const bool& value, bool display);
    bool          getShadows();
    void          setCamPosition(const Ogre::Vector3& value, bool display);
    Ogre::Vector3 getCamPosition();
    void          setCamOrientation(const Ogre::Quaternion& value, bool display);
    Ogre::Quaternion getCamOrientation();
    void          setCamClipDistance(const Ogre::Vector2& value, bool display);
    Ogre::Vector2 getCamClipDistance();
    void          setCamPolyMode(const int& value, bool display);
    int           getCamPolyMode();
    void          setCamFOV(const Ogre::Real& value, bool display);
    Ogre::Real    getCamFOV();
    void          setColour(const Ogre::ColourValue& value, bool display);
    Ogre::ColourValue getColour();

    void          removeCompositor(const Ogre::String& name);
    virtual bool  load();
    virtual bool  unLoad();
    virtual void  processParameters(Ogre::NameValuePairList &params);
    virtual bool  handleCustomFunction(int BIND_ID,Ogre::String val);
	/// This function is called when user right clicks a property to get that property specific popup menu
	/// returns false if no menu present (Disabled Menu Items has a "D" prefix where Enabled Menu Items have "E" prefix
	virtual bool  getPropertyContextMenu(unsigned int itemid, UTFStringVector &menuitems);
	
    /// This function is called when user selects a menuitem from ContextMenu
	virtual void  onPropertyContextMenu(unsigned int itemid, int menuresult);

    virtual void  setNameImpl(Ogre::String name, bool display);
    virtual void  showBoundingBox(bool bShow) {};
    virtual bool  setupPropertiesWnd(bool present);
    virtual void  getObjectProperties(Ogre::NameValuePairList &retList);
    /// Overridden by Editor Objects to Import Object Dependant Properties
    virtual void  restore(Ogre::NameValuePairList &retList);
    /// Gets the Handle to encapsulated object
    inline virtual void *getHandle() {return static_cast<void*>(m_Handle);};
	
    virtual void         pushCompositors(Ogre::Camera *camera);

    virtual void         popCompositors();

    int                  getRect(Ogre::Vector4 &rect);

    virtual void         setCameraEditor(CCameraEditor *camed);
    inline CCameraEditor *getCameraEditor() {return m_ActiveCamera;};
    inline CCameraEditor *getViewCameraEditor() {return m_ViewCamera;};
    void                 renderWindowResized();

protected:
	Ogre::Viewport    *m_Handle;
    unsigned int       m_ViewportIndex;
    Ogre::Vector4      m_Dimensions;
    bool               m_Overlays;
    bool               m_Skies;
    bool               m_Shadows;
    Ogre::Vector3      m_CamPosition;
    Ogre::Quaternion   m_CamOrientation;
    Ogre::Vector2      m_CamClipDistance;
    int                m_CamPolyMode;
    Ogre::Real         m_CamFOV;
    Ogre::ColourValue  m_Colour;

    std::vector<COMPOSITORPUSH> m_CompositorStorage;
    CCameraEditor     *m_ActiveCamera;
    CCameraEditor     *m_ViewCamera;

	CViewportEditor();
	virtual                ~CViewportEditor();
    virtual void           _createViewport();
    void                   _handleCompositorProperties(int BIND_ID,Ogre::String& val);


    /// EVENTS INTERFACE RELATED

protected:
    Ogre::Vector2       m_LastMouse;
    Ogre::Vector2       m_LastClickPoint;
    int                 m_LastButtons;
	Ogre::Plane         m_LastUsedPlane;
	Ogre::Vector3       m_LastPosition;
	Ogre::Vector3       m_LastDerivedPosition;
	Ogre::Vector3       m_LastScale;
	Ogre::Quaternion    m_LastOrient;
	Ogre::Quaternion    m_LastDerivedOrient;
	Ogre::Vector3       m_Last3DDelta;
	Ogre::Vector3       m_NewCamPosition;
    ViewportGrid       *m_ViewGrid;
	bool                m_GridVisible;
    bool                m_VolumeSelecting;
    bool                m_FirstTimeTranslation;
    
    static NameObjectPairList  m_HighLighted;
	static int                 m_EditorTool;
	static int                 m_EditorToolEx;
	static int                 m_EditorAxis;
	static float               m_CameraSpeed;
    static bool                m_IsEditing;
    static bool                m_IsSettingPos;
    static OgitorsUndoManager *m_UndoManager;

public:
    static bool               *m_ViewKeyboard;
    static OgitorsSpecialKeys  m_Special;

    static void  ResetCommonValues();
    static void SetKeyboard(bool *keyboard, OgitorsSpecialKeys &keys) {m_ViewKeyboard = keyboard;m_Special = keys;};
    static OgitorsSpecialKeys GetKeyboard() {return m_Special;};

    void  MultiplyCameraSpeed(float value) {m_CameraSpeed *= value;};
    void  SetCameraSpeed(float value) {m_CameraSpeed = value;};
    float GetCameraSpeed() {return m_CameraSpeed;};
    virtual void  SetEditorTool(unsigned int tool);
    static unsigned int GetEditorTool() {return m_EditorTool;};
    virtual void  SetEditorAxis(unsigned int axis) {m_EditorAxis = axis;};
    static unsigned int GetEditorAxis() {return m_EditorAxis;};
    virtual void SetLastMouse(Ogre::Vector2 mousepos) {m_LastMouse = mousepos;};
    bool GetMouseRay( Ogre::Vector2 point, Ogre::Ray &mRay );
	virtual void SaveEditorStates(Ogre::Ray &mouseRay);
	virtual void DoSelect(Ogre::Ray &mouseRay);
	virtual void CloneMove();
	virtual void UpdateAutoCameraPosition(float time);
    virtual void HighlightObjectAtPosition(Ogre::Ray &mouseRay);
    ViewportGrid* GetViewGrid() {return m_ViewGrid;};
	bool IsGridVisible() {return m_GridVisible;};
	virtual void ShowGrid() {m_GridVisible = !m_GridVisible;m_ViewGrid->setEnabled(m_GridVisible);}
	virtual void FocusSelectedObject();
	virtual void DeleteSelectedObject(bool silent = false, bool withundo = true);
	virtual void ProcessKeyActions(unsigned int timesince);
	virtual void LoadEditorObjects();

	/** Keyboard events callback.
	@remarks This will handle Key Down Event.
	@param evt Data regarding the key event.
	*/
	virtual void OnKeyDown (unsigned int key);

	/** Keyboard events callback.
	@remarks This will handle Key Up Event.
	@param evt Data regarding the key event.
	*/
	virtual void OnKeyUp (unsigned int key);

	/** Mouse events callback.
	@remarks This will handle Mouse Move Event.
	@param evt Data regarding the mouse event.
	*/
    virtual void OnMouseMove (Ogre::Vector2 point, unsigned int buttons, bool imitate = false);

	/** Mouse events callback.
	@remarks This will handle Mouse Leave Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseLeave (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Left Mouse Down Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseLeftDown (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Left Mouse Up Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseLeftUp (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Right Mouse Down Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseRightDown (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Middle Mouse Down Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseMiddleDown (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Middle Mouse Up Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseMiddleUp (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Right Mouse Up Event.
	@param evt Data regarding the mouse event.
	*/
	virtual void OnMouseRightUp (Ogre::Vector2 point, unsigned int buttons);

	/** Mouse events callback.
	@remarks This will handle Mouse Wheel Event.
	@param evt Data regarding the mouse event.
	*/
    virtual void OnMouseWheel (Ogre::Vector2 point, float delta, unsigned int buttons);

    virtual void DoVolumeSelect();

    virtual void ClearSelection();

    virtual CBaseEditor* GetObjectUnderMouse(Ogre::Ray &mouseRay, bool pickwidgets = false, bool pickterrain = false);

    virtual void UpdateAfterMoveRotateScale();

    virtual void PrepareTranslationUndo();

	bool GetHitPosition(Ogre::Ray &mouseRay, Ogre::Vector3& position, const Ogre::String& excludeobject = "");
	bool GetHitPosition(Ogre::Ray &mouseRay, Ogre::Vector3& position, const Ogre::StringVector& excludeobjects);
};

class OgitorExport CViewportEditorFactory: public CBaseEditorFactory
{
public:
  unsigned int mLastZOrder;
    
  CViewportEditorFactory();
  virtual ~CViewportEditorFactory() {};
  virtual void Init();
  virtual CBaseEditor *CreateObject(CBaseEditor **parent, Ogre::NameValuePairList &params);
  virtual void DestroyObject(CBaseEditor *object);
};
}
